/******************************************************************************
 *      Mestrado em Ciência da Computação - UFMS
 *		Redes de Computadores - Prof. Dr. Ronaldo Alves Ferreira
 *		Alunos: Geraldo Landre, Marcel Tolentino, Vinícius Bueno
 *****************************************************************************/

#include "request.h"
#include "enums.h"

cache_control* new_cache_control()
{
    cache_control *cc = (cache_control *) malloc(sizeof(cache_control));

    cc->cache_extension = NULL;
    cc->field_name = NULL;
    cc->is_public = 1;
    cc->max_age = 0;
    cc->max_stale = 0;
    cc->min_fresh = 0;
    cc->must_revalidate = 0;
    cc->no_cache = 0;
    cc->no_store = 0;
    cc->no_transform = 0;
    cc->only_if_cached = 0;
    cc->proxy_revalidate = 0;
    cc->s_maxage = 0;

    return cc;
}

void print_cache_control(cache_control *cc)
{
    printf("Cache-Control:");
    if(cc->is_public)
        printf("public, ");
    else
        printf("private, ");

    if(cc->max_age)
        printf("max-age = %i, ",cc->max_age);
    if(cc->max_stale)
        printf("max-stale = %i, ",cc->max_stale);
    if(cc->min_fresh)
        printf("min-fresh = %i, ",cc->min_fresh);
    if(cc->must_revalidate)
        printf("must-revalidate, ");
    if(cc->no_cache)
        printf("no-cache, ");
    if(cc->no_store)
        printf("no-store, ");
    if(cc->no_transform)
        printf("no-transform, ");
    if(cc->only_if_cached)
        printf("only-if-cached, ");
    if(cc->proxy_revalidate)
        printf("proxy-revalidate, ");
    if(cc->s_maxage)
        printf("s-maxage = %i, ",cc->s_maxage);
    printf("\n\n");
}

header_data * new_header()
{
    int i;
    header_data *hd = (header_data *) malloc(sizeof(header_data));
    hd->header = (vstring **) malloc(50 * sizeof(vstring *));
    hd->age = 0;
    hd->alive = 1;
    hd->last_irc = -2;

    for(i = 0; i < 8; i++)
        hd->allow[i] = 0;
    for(i = 0; i < 50; i++)
        hd->header[i] = NULL;

    hd->cache_params = new_cache_control();
    hd->chunked = 0;
    hd->content_length = 0;
    hd->end = 0;
    hd->error = 0;
    hd->is_response = 0;
    hd->method = 0;

    hd->content_location = NULL;
    hd->host = NULL;
    hd->http = NULL;
    hd->method_str = NULL;
    hd->msg = NULL;
    hd->port = NULL;
    hd->request = NULL;
    hd->srv_port = NULL;
    hd->srv_request = NULL;
    hd->srv_url = NULL;

    hd->date = NULL;
    hd->expires = NULL;

    return hd;
}

void reset_header(header_data **hd)
{
    int i;
    (*hd)->age = 0;
    (*hd)->alive = 1;

    for(i = 0; i < 8; i++)
        (*hd)->allow[i] = 0;

    (*hd)->cache_params = new_cache_control();
    (*hd)->chunked = 0;
    (*hd)->content_length = 0;
    (*hd)->end = 0;
    (*hd)->error = 0;
    (*hd)->is_response = 0;
    (*hd)->method = 0;

    free_string(&((*hd)->content_location));
    free_string(&((*hd)->host));
    free_string(&((*hd)->http));
    free_string(&((*hd)->method_str));
    free_string(&((*hd)->msg));
    free_string(&((*hd)->port));
    free_string(&((*hd)->request));
    free_string(&((*hd)->srv_port));
    free_string(&((*hd)->srv_request));
    free_string(&((*hd)->srv_url));

    for(i = 0; i < 50; i++)
        free_string(&((*hd)->header[i]));

    free((*hd)->cache_params);
    (*hd)->cache_params = NULL;
    (*hd)->cache_params = new_cache_control();

    free((*hd)->date);
    (*hd)->date = NULL;
    free((*hd)->expires);
    (*hd)->expires = NULL;
}

void copy_header_data(header_data **oldhd,header_data **newhd)
{
    int i;

    (*newhd)->age = (*oldhd)->age;
    (*newhd)->alive = (*oldhd)->alive;

    for(i = 0; i < 8; i++)
        (*newhd)->allow[i] = (*oldhd)->allow[i];

    (*newhd)->last_irc = (*oldhd)->last_irc;
    (*newhd)->client_socket = (*oldhd)->client_socket;
    (*newhd)->chunked = (*oldhd)->chunked;
    (*newhd)->content_length = (*oldhd)->content_length;
    (*newhd)->end = (*oldhd)->end;
    (*newhd)->error = (*oldhd)->error;
    (*newhd)->is_response = (*oldhd)->is_response;
    (*newhd)->method = (*oldhd)->method;
    copy_vstring(&((*newhd)->content_location),(*oldhd)->content_location);
    copy_vstring(&((*newhd)->host),(*oldhd)->host);
    copy_vstring(&((*newhd)->http),(*oldhd)->http);
    copy_vstring(&((*newhd)->method_str),(*oldhd)->method_str);
    //copy_vstring(&((*oldhd)->msg),(*newhd)->msg);
    copy_vstring(&((*newhd)->port),(*oldhd)->port);
    copy_vstring(&((*newhd)->request),(*oldhd)->request);
    copy_vstring(&((*newhd)->srv_port),(*oldhd)->srv_port);
    copy_vstring(&((*newhd)->srv_request),(*oldhd)->srv_request);
    copy_vstring(&((*newhd)->srv_url),(*oldhd)->srv_url);
}

int is_empty(header_data *hd)
{
    int i;
    for(i = 1; i < 50; i++)
        if(!is_null(&(hd->header[i])))
            return 0;
    return 1;
}

void print_header_data(const header_data *hd)
{
    int i;
    printf("_________________CONTEÚDO HEADER_DATA________________________\n");
    if(hd->msg != NULL)
        printf("msg_length: %i\n",hd->msg->length);
    printf("end: %i\n",hd->end);
    printf("error: %i\n",hd->error);
    if(hd->age)
        printf("Age: %i\n",hd->age);
    printf("Alive: %i\n",hd->alive);
    printf("Allow: ");
    for(i = 1; i < 8; i++)
        printf("%i ",hd->allow[i]);
    printf("\n");

    if(hd->content_length)
        printf("Content-Length: %i\n",hd->content_length);
    if(hd->date != NULL)
        printf("Date: %s",asctime(hd->date));
    if(hd->expires != NULL)
        printf("Expires: %s",asctime(hd->expires));
    if(hd->cache_params != NULL)
        print_cache_control(hd->cache_params);

    printf("Content-Location: ");
    print_string(hd->content_location);
    printf("Host: ");
    print_string(hd->host);
    printf("Http: ");
    print_string(hd->http);
    printf("Method: ");
    print_string(hd->method_str);
    printf("Port: ");
    print_string(hd->port);
    printf("Request: ");
    print_string(hd->request);
    printf("Srv-Port: ");
    print_string(hd->srv_port);
    printf("Srv-Request: ");
    print_string(hd->srv_request);
    printf("Srv-Url: ");
    print_string(hd->srv_url);
    printf("Msg: (comentado)\n\n");
    print_string(hd->msg);
    for(i = 0; i < 50; i++)
        if(!is_null(&(hd->header[i])))
            print_string(hd->header[i]);
    printf("___________________________________________________________\n\n");
}

/*	Verifica o erro na variável global 'httperr' e retorna
	a mensagem correspondente	*/
char* get_str_httperror(int error)
{
    switch(error)
    {        
        case MSG_CONTINUE:           
            return "100 Continue";  //  100,
        case MSG_SWITCHING_PROTOCOLS:
            return "101 Switching Protocols";  //  101,
        case MSG_OK:                            
            return "200 OK";  //  200,
        case MSG_CREATED:                       
            return "201 Created";  //  201,
        case MSG_ACCEPTED:                      
            return "202 Accepted";  //  202,
        case MSG_NON_AUTHORITATIVE_INFORMATION: 
            return "203 Non-Authoritative Information";  //  203,
        case MSG_NO_CONTENT:                    
            return "204 No Content";  //  204,
        case MSG_RESET_CONTENT:                 
            return "205 Reset Content";  //  205,
        case MSG_PARTIAL_CONTENT:               
            return "206 Partial Content";  //  206,
        case ERR_MULTIPLE_CHOICES:              
            return "300 Multiple Choices";  //  300,
        case ERR_MOVED_PERMANENTLY:             
            return "301 Moved Permanently";  //  301,
        case ERR_FOUND:                         
            return "302 Found";  //  302,
        case ERR_SEE_OTHER:                     
            return "303 See Other";  //  303,
        case ERR_NOT_MODIFIED:                  
            return "304 Not Modified";  //  304,
        case ERR_USE_PROXY:                     
            return "305 Use Proxy";  //  305,
        case ERR_TEMPORARY_REDIRECT:            
            return "307 Temporary Redirect";  //  307,
        case ERR_BAD_REQUEST:                   
            return "400 Bad Request";  //  400,
        case ERR_UNAUTHORIZED:                  
            return "401 Unauthorized";  //  401,
        case ERR_PAYMENT_REQUIRED:              
            return "402 Payment Required";  //  402,
        case ERR_FORBIDDEN:                     
            return "403 Forbidden";  //  403,
        case ERR_NOT_FOUND:                     
            return "404 Not Found";  //  404,
        case ERR_METHOD_NOT_ALLOWED:            
            return "405 Method Not Allowed";  //  405,
        case ERR_NOT_ACCEPTABLE:                
            return "406 Not Acceptable";  //  406,
        case ERR_PROXY_AUTHENTICATION_REQUIRED: 
            return "407 Proxy Authentication Required";  //  407,
        case ERR_REQUEST_TIME_OUT:              
            return "408 Request Time-out";  //  408,
        case ERR_CONFLICT:                      
            return "409 Conflict";  //  409,
        case ERR_GONE:                          
            return "410 Gone";  //  410,
        case ERR_LENGTH_REQUIRED:               
            return "411 Length Required";  //  411,
        case ERR_PRECONDITION_FAILED:           
            return "412 Precondition Failed";  //  412,
        case ERR_REQUEST_ENTITY_TOO_LARGE:      
            return "413 Request Entity Too Large";  //  413,
        case ERR_REQUEST_URI_TOO_LARGE:          
            return "414 Request-URI Too Large";  //  414,
        case ERR_UNSUPPORTED_MEDIA_TYPE:        
            return "415 Unsupported Media Type";  //  415,
        case ERR_REQUESTED_RANGE_NOT_SATISFIABLE:
            return "416 request Range Not Satisfiable";  //  416,
        case ERR_EXPECTATION_FAILED:             
            return "417 Expectation Failed";  //  417,
        case ERR_INTERNAL_SERVER_ERROR:     
            return "500 Internal Server Error";  //  500,    
        case ERR_NOT_IMPLEMENTED:           
            return "501 Not Implemented";  //  501,
        case ERR_BAD_GATEWAY:               
            return "502 Bad Gateway";  //  502,
        case ERR_SERVICE_UNAVAILABLE:       
            return "503 Service Unavailable";  //  503,
        case ERR_GATEWAY_TIME_OUT:          
            return "504 Gateway Time-out";  //  504,
        case ERR_HTTP_VERSION_NOT_SUPPORTED:
            return "505 HTTP Version not supported";  //  505

        default:
            return "400 Bad Request";
    }
}

int is_cacheable(header_data *hd)
{
    return (hd->error == MSG_OK && hd->cache_params->is_public);// && !hd->cache_params->no_store);
}